package com.acmen.easyapi.parse;

import com.acmen.easyapi.model.Dependency;
import com.acmen.easyapi.util.StringUtil;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * PomParser类用于解析pom文件生成依赖对象
 *
 * @author acmen
 */
public class PomParser {
    private static final Logger log = LoggerFactory.getLogger(PomParser.class);

    private static String KEY_GROUP_ID = "groupId";
    private static String KEY_ARTIFACT_ID = "artifactId";
    private static String KEY_VERSION = "version";
    private static String KEY_PARENT = "parent";

    private static Map<String,Dependency> dependencyMap = new HashMap<>();

    /**
     * 根据给定的类的全限定名生成依赖
     * @param pomResources 模块的pom资源的映射表
     * @param clazz 传入的类
     * @return 生成的依赖对象
     * @throws IOException 当发生I/O错误时抛出该异常
     * @throws DocumentException 当解析文档时发生错误时抛出该异常
     */
    public static Dependency genDependency(Map<String, InputStream> pomResources, Class clazz) throws IOException, DocumentException {
        String classPath = clazz.getName().replace(".", "/")+".class";
        Enumeration<URL> urls = PomParser.class.getClassLoader().getResources(classPath);

        while (urls.hasMoreElements()) {
            URL url = urls.nextElement();
            // 获取资源的文件路径
            String filePath = url.getPath();
            // 判断文件路径是否包含 ".jar!"
            int idx = filePath.lastIndexOf(".jar!");
            if (idx > 0) {
                // 如果包含，则获取 jar 文件的路径
                String jarFilePath = filePath.substring(0, idx + 4);
                // 如果依赖映射中已存在该 jar 文件路径
                if (dependencyMap.containsKey(jarFilePath)) {
                    // 直接返回该依赖
                    return dependencyMap.get(jarFilePath);
                }
                // 如果 inputStream 不为空
                InputStream inputStream = pomResources.get(jarFilePath);
                if (inputStream != null) {
                    // 获取 pom 文件的依赖
                    Dependency dependency = getDependency(inputStream);
                    // 将 jar 文件路径与依赖添加到依赖映射中
                    dependencyMap.put(jarFilePath, dependency);
                    // 返回依赖
                    return dependency;
                }
            } else {
                // 判断文件路径是否包含 "target/classes/"
                int index = filePath.indexOf("target/classes/");
                if (index > 0) {
                    // 如果包含，则获取 pom 文件的路径
                    String pomFilePath = filePath.substring(0, index) + "pom.xml";
                    pomFilePath = pomFilePath.replace("%20", " ");
                    // 如果依赖映射中已存在该 pom 文件路径
                    if (dependencyMap.containsKey(pomFilePath)) {
                        // 直接返回该依赖
                        return dependencyMap.get(pomFilePath);
                    }
                    // 创建 pom 文件的路径
                    File pomFile = new File(pomFilePath);
                    if (pomFile.exists()) {
                        // 如果 pom 文件存在，则创建输入流并获取依赖
                        InputStream inputStream = new FileInputStream(pomFile);
                        Dependency dependency = getDependency(inputStream);
                        // 将 pom 文件路径与依赖添加到依赖映射中
                        dependencyMap.put(pomFilePath, dependency);
                        // 返回依赖
                        return dependency;
                    }
                }
            }
        }
        return null;
    }

    /**
     * 从输入流中获取依赖对象
     *
     * @param inputStream 输入流对象
     * @return 生成的依赖对象
     * @throws IOException 当发生I/O错误时抛出该异常
     * @throws DocumentException 当解析文档时发生错误时抛出该异常
     */
    private static Dependency getDependency(InputStream inputStream) throws IOException, DocumentException {
        // 创建一个 StringBuilder 对象用于存储内容
        StringBuilder content = new StringBuilder();
        // 创建一个 byte 数组用于存储读取到的数据
        byte[] b = new byte[2];
        // 当从输入流中读取的数据不等于 -1 时，循环读取数据
        while (inputStream.read(b) != -1) {
            // 将 byte 数组转换为 UTF-8 编码的字符串
            String str = new String(b, "utf-8");
            // 将字符串追加到 StringBuilder 对象中
            content.append(str);
        }
        // 将 StringBuilder 对象转换为字符串并去除首尾空白字符
        String xml = content.toString().trim();
        // 获取 XML 字符串中 </project> 标签的最后一个位置
        int idx = xml.lastIndexOf("</project>");
        // 将 XML 字符串截取到 </project> 标签为止
        xml = xml.substring(0, idx+"</project>".length());
        // 解析 XML 字符串并创建一个 Document 对象
        Document doc = DocumentHelper.parseText(xml);
        // 获取根元素
        Element root = doc.getRootElement();
        // 获取根元素中的 PARENT 标签
        Element parent = root.element(KEY_PARENT);
        // 初始化 GROUP_ID 变量
        String groupId = null;
        // 如果根元素中存在 GROUP_ID 标签，则将其中的文本内容赋值给 GROUP_ID 变量
        if (root.element(KEY_GROUP_ID) != null) {
            groupId = root.element(KEY_GROUP_ID).getTextTrim();
        }
        // 如果 PARENT 标签不为空且其中存在 GROUP_ID 标签，则将其中的文本内容赋值给 GROUP_ID 变量
        else if (parent != null && parent.element(KEY_GROUP_ID) != null) {
            groupId = parent.element(KEY_GROUP_ID).getTextTrim();
        }
        // 获取根元素中的 ARTIFACT_ID 标签，如果存在则将其中的文本内容赋值给 ARTIFACT_ID 变量
        String artifactId = root.element(KEY_ARTIFACT_ID) != null ? root.element(KEY_ARTIFACT_ID).getTextTrim() : "";
        // 获取根元素中的 VERSION 标签，如果存在则将其中的文本内容赋值给 VERSION 变量
        String version = root.element(KEY_VERSION) != null ? root.element(KEY_VERSION).getTextTrim() : "";
        // 如果 VERSION 变量的值等于 "${project.parent.version}"
        if ("${project.parent.version}".equals(version)) {
            // 将 PARENT 标签中的 VERSION 标签的文本内容赋值给 VERSION 变量
            version = parent.element(KEY_VERSION).getTextTrim();
        }
        // 如果 VERSION 变量为空
        if (StringUtil.isEmpty(version)) {
            // 将 PARENT 标签中的 VERSION 标签的文本内容赋值给 VERSION 变量
            version = parent.element(KEY_VERSION).getTextTrim();
        }
        // 创建一个 Dependency 对象，传入 GROUP_ID、ARTIFACT_ID 和 VERSION 变量的值
        Dependency dependency = new Dependency(groupId, artifactId, version);
        // 返回 Dependency 对象
        return dependency;
    }

    /**
     * 获取所有 pom 资源的映射表
     *
     * @return 包含所有 pom 资源的映射表
     */
    public static Map<String, InputStream> getPomResources() {
                // 定义匹配资源的模式
        String pattern = "classpath*:/META-INF/maven/**/pom.xml";
        Resource[] resources = new Resource[0];
        try {
            resources = new PathMatchingResourcePatternResolver().getResources(pattern);
        } catch (IOException e) {
            e.printStackTrace();
            return new HashMap<>();
        }
        // 将获取的资源存储在哈希表中
        Map<String, InputStream> resourceMap = new HashMap<>();

        // 遍历获取的资源
        for (Resource resource : resources) {
            try {
                // 获取资源的文件路径
                String filePath = resource.getURL().getPath();
                // 判断文件路径是否包含 ".jar!"
                int idx = filePath.lastIndexOf(".jar!");
                if (idx > 0) {
                    // 如果包含，则获取 jar 文件的路径
                    String jarFilePath = filePath.substring(0, idx + 4);
                    resourceMap.put(jarFilePath, resource.getInputStream());
                } else {
                    resourceMap.put(filePath, resource.getInputStream());
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        // 返回资源哈希表
        return resourceMap;

    }

    public static void main(String[] args) {
        Map map = getPomResources();
        System.out.print(map);
    }
}
